import { Command } from "commander";
import { NetworkConfigurator } from "./CreateNetwork";
import { AWSUpload } from "./AWSUpload";
import { Deployer } from "./Deployer";

export type CreateArgs = {
    consensus: "pos" | "poa";
    validatorCount: number;
    exportPath: string;
    password: string;
    upload: boolean;
    secretIds: string[];
    deploy: boolean;
    keyPath?: string;
    nodeIps: string[];
};

const parse = (args: any): CreateArgs | undefined => {
    const validNumber = (n: any): boolean => !isNaN(Number(n)) && Number(n) > 0;
    if (
        args.consensus &&
        (args.consensus === "pos" || args.consensus === "poa") &&
        validNumber(args.validatorCount) &&
        args.exportPath &&
        typeof args.exportPath === "string" &&
        (!args.password || (args.password && typeof args.password === "string" && args.password.length >= 8)) &&
        ((!!args.upload && args.secretIds && typeof args.secretIds === "string") || !args.upload) &&
        ((!!args.deploy && args.keyPath && typeof args.keyPath === "string" && args.nodeIps && typeof args.nodeIps === "string") ||
            !args.deploy)
    ) {
        const parsedSecretIds: string[] = (args.secretIds || "").split(",");
        const parsedNodeIps: string[] = (args.nodeIps || "").split(",");
        return {
            consensus: args.consensus,
            validatorCount: args.validatorCount,
            exportPath: args.exportPath,
            password: args.password,
            upload: !!args.upload,
            secretIds: args.upload ? parsedSecretIds : [],
            deploy: !!args.deploy,
            keyPath: args.keyPath,
            nodeIps: args.nodeIps ? parsedNodeIps : [],
        };
    }
    return undefined;
};

const program = new Command("create")
    .option("-c, --consensus <pos|poa>", "The type of consensus of the network")
    .option("-v, --validator-count <number>", "The number of validators")
    .option("-e, --export-path <value>", "The path to export the node assets")
    .option("-p, --password <value>", "The password to encrypt the node assets")
    .option("-u, --upload", "Upload assets to aws")
    .option("-s, --secret-ids <value>", "AWS Secret Id to upload node configs")
    .option("-d, --deploy", "Deploy network to servers")
    .option("-k, --key-path <value>", "SSH Key to access the servers")
    .option("-n, --node-ips <value>", "Node ips (comma separated)")
    .action(async (args) => {
        const parsedArgs = parse(args);
        if (parsedArgs) {
            const runner = new NetworkConfigurator(
                parsedArgs.consensus,
                parsedArgs.validatorCount,
                parsedArgs.exportPath,
                parsedArgs.password,
            );
            const uploadRunner = new AWSUpload(parsedArgs.consensus, parsedArgs.exportPath, parsedArgs.password, parsedArgs.secretIds);
            const deployRunner = new Deployer(parsedArgs.exportPath, parsedArgs.nodeIps, parsedArgs.password, parsedArgs.keyPath!);
            try {
                await runner.run();
                if (parsedArgs.upload) await uploadRunner.run();
                if (parsedArgs.deploy) await deployRunner.run();
            } catch (error) {
                console.log(error);
                process.exit(1);
            }
            process.exit(0);
        } else {
            program.help();
            process.exit(1);
        }
    });
export default program;
